#include "wifi_board.h"

#include "display.h"
#include "application.h"
#include "system_info.h"
#include "font_awesome_symbols.h"
#include "settings.h"
#include "assets/lang_config.h"

#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <esp_http.h>
#include <esp_mqtt.h>
#include <esp_udp.h>
#include <tcp_transport.h>
#include <tls_transport.h>
#include <web_socket.h>
#include <esp_log.h>

#include <wifi_station.h>
#include <wifi_configuration_ap.h>
#include <ssid_manager.h>

static const char *TAG = "WifiBoard";

/**
 * @brief WiFi开发板构造函数
 * 
 * 初始化WiFi开发板，检查是否需要强制进入配网模式
 */
WifiBoard::WifiBoard() {
    Settings settings("wifi", true);
    wifi_config_mode_ = settings.GetInt("force_ap") == 1;
    if (wifi_config_mode_) {
        ESP_LOGI(TAG, "force_ap is set to 1, reset to 0");
        settings.SetInt("force_ap", 0);
    }
}

/**
 * @brief 获取开发板类型
 * 
 * @return std::string 返回"wifi"作为开发板类型标识
 */
std::string WifiBoard::GetBoardType() {
    return "wifi";
}

/**
 * @brief 进入WiFi配网模式
 * 
 * 启动WiFi接入点，允许用户通过手机或电脑连接并配置WiFi
 */
void WifiBoard::EnterWifiConfigMode() {
    auto& application = Application::GetInstance();
    application.SetDeviceState(kDeviceStateWifiConfiguring);

    auto& wifi_ap = WifiConfigurationAp::GetInstance();
    wifi_ap.SetLanguage(Lang::CODE);
    wifi_ap.SetSsidPrefix("Xiaozhi");
    wifi_ap.Start();

    // 显示 WiFi 配置 AP 的 SSID 和 Web 服务器 URL
    std::string hint = Lang::Strings::CONNECT_TO_HOTSPOT;
    hint += wifi_ap.GetSsid();
    hint += Lang::Strings::ACCESS_VIA_BROWSER;
    hint += wifi_ap.GetWebServerUrl();
    hint += "\n\n";
    
    // 播报配置 WiFi 的提示
    application.Alert(Lang::Strings::WIFI_CONFIG_MODE, hint.c_str(), "", Lang::Sounds::P3_WIFICONFIG);
    
    // 无限等待，直到配置完成后重启设备
    while (true) {
        int free_sram = heap_caps_get_free_size(MALLOC_CAP_INTERNAL);
        int min_free_sram = heap_caps_get_minimum_free_size(MALLOC_CAP_INTERNAL);
        ESP_LOGI(TAG, "Free internal: %u minimal internal: %u", free_sram, min_free_sram);
        vTaskDelay(pdMS_TO_TICKS(10000));
    }
}

/**
 * @brief 启动网络连接
 * 
 * 尝试连接WiFi网络，如果没有配置或连接失败则进入配网模式
 */
void WifiBoard::StartNetwork() {
    // 如果用户在启动时按下BOOT按钮，进入WiFi配置模式
    if (wifi_config_mode_) {
        EnterWifiConfigMode();
        return;
    }

    // 如果没有配置WiFi SSID，进入WiFi配置模式
    auto& ssid_manager = SsidManager::GetInstance();
    auto ssid_list = ssid_manager.GetSsidList();
    if (ssid_list.empty()) {
        wifi_config_mode_ = true;
        EnterWifiConfigMode();
        return;
    }

    auto& wifi_station = WifiStation::GetInstance();
    // 设置WiFi扫描开始回调
    wifi_station.OnScanBegin([this]() {
        auto display = Board::GetInstance().GetDisplay();
        display->ShowNotification(Lang::Strings::SCANNING_WIFI, 30000);
    });
    // 设置WiFi连接开始回调
    wifi_station.OnConnect([this](const std::string& ssid) {
        auto display = Board::GetInstance().GetDisplay();
        std::string notification = Lang::Strings::CONNECT_TO;
        notification += ssid;
        notification += "...";
        display->ShowNotification(notification.c_str(), 30000);
    });
    // 设置WiFi连接成功回调
    wifi_station.OnConnected([this](const std::string& ssid) {
        auto display = Board::GetInstance().GetDisplay();
        std::string notification = Lang::Strings::CONNECTED_TO;
        notification += ssid;
        display->ShowNotification(notification.c_str(), 30000);
    });
    wifi_station.Start();

    // 尝试连接WiFi，如果60秒内连接失败，则启动WiFi配置AP
    if (!wifi_station.WaitForConnected(60 * 1000)) {
        wifi_station.Stop();
        wifi_config_mode_ = true;
        EnterWifiConfigMode();
        return;
    }
}

/**
 * @brief 创建HTTP客户端实例
 * 
 * @return Http* 返回新创建的HTTP客户端对象
 */
Http* WifiBoard::CreateHttp() {
    return new EspHttp();
}

/**
 * @brief 创建WebSocket客户端实例
 * 
 * 根据配置创建适当的WebSocket客户端，支持WSS和WS协议
 * 
 * @return WebSocket* 返回新创建的WebSocket客户端对象，如未配置则返回nullptr
 */
WebSocket* WifiBoard::CreateWebSocket() {
#ifdef CONFIG_CONNECTION_TYPE_WEBSOCKET
    std::string url = CONFIG_WEBSOCKET_URL;
    if (url.find("wss://") == 0) {
        return new WebSocket(new TlsTransport());
    } else {
        return new WebSocket(new TcpTransport());
    }
#endif
    return nullptr;
}

/**
 * @brief 创建MQTT客户端实例
 * 
 * @return Mqtt* 返回新创建的MQTT客户端对象
 */
Mqtt* WifiBoard::CreateMqtt() {
    return new EspMqtt();
}

/**
 * @brief 创建UDP客户端实例
 * 
 * @return Udp* 返回新创建的UDP客户端对象
 */
Udp* WifiBoard::CreateUdp() {
    return new EspUdp();
}

/**
 * @brief 获取网络状态图标
 * 
 * 根据WiFi连接状态和信号强度返回对应的图标
 * 
 * @return const char* 返回表示网络状态的字体图标
 */
const char* WifiBoard::GetNetworkStateIcon() {
    if (wifi_config_mode_) {
        return FONT_AWESOME_WIFI;
    }
    auto& wifi_station = WifiStation::GetInstance();
    if (!wifi_station.IsConnected()) {
        return FONT_AWESOME_WIFI_OFF;
    }
    int8_t rssi = wifi_station.GetRssi();
    if (rssi >= -60) {
        return FONT_AWESOME_WIFI;
    } else if (rssi >= -70) {
        return FONT_AWESOME_WIFI_FAIR;
    } else {
        return FONT_AWESOME_WIFI_WEAK;
    }
}

/**
 * @brief 获取开发板JSON配置
 * 
 * 生成包含开发板信息的JSON字符串，用于OTA和状态报告
 * 
 * @return std::string 包含开发板配置的JSON字符串
 */
std::string WifiBoard::GetBoardJson() {
    // 设置OTA用的开发板类型
    auto& wifi_station = WifiStation::GetInstance();
    std::string board_json = std::string("{\"type\":\"" BOARD_TYPE "\",");
    board_json += "\"name\":\"" BOARD_NAME "\",";
    if (!wifi_config_mode_) {
        board_json += "\"ssid\":\"" + wifi_station.GetSsid() + "\",";
        board_json += "\"rssi\":" + std::to_string(wifi_station.GetRssi()) + ",";
        board_json += "\"channel\":" + std::to_string(wifi_station.GetChannel()) + ",";
        board_json += "\"ip\":\"" + wifi_station.GetIpAddress() + "\",";
    }
    board_json += "\"mac\":\"" + SystemInfo::GetMacAddress() + "\"}";
    return board_json;
}

/**
 * @brief 设置WiFi省电模式
 * 
 * @param enabled true启用省电模式，false禁用省电模式
 */
void WifiBoard::SetPowerSaveMode(bool enabled) {
    auto& wifi_station = WifiStation::GetInstance();
    wifi_station.SetPowerSaveMode(enabled);
}

/**
 * @brief 重置WiFi配置
 * 
 * 设置标志并重启设备，使其进入网络配置模式
 */
void WifiBoard::ResetWifiConfiguration() {
    // 设置标志并重启设备进入网络配置模式
    {
        Settings settings("wifi", true);
        settings.SetInt("force_ap", 1);
    }
    GetDisplay()->ShowNotification(Lang::Strings::ENTERING_WIFI_CONFIG_MODE);
    vTaskDelay(pdMS_TO_TICKS(1000));
    // 重启设备
    esp_restart();
}
